Authors

Astarte Brown

Joffrey Joumaa

Published

April 11, 2023

1 Import library

Code
# data viz
library(ggplot2)
library(ggh4x)
library(ggOceanMaps)
library(patchwork)
library(viridis)
library(ggpubr)
library(grid)
library(viridis)
library(ggnewscale)

# table
library(gt)

# map
library(ggmap)
library(ggsn)
library(sf)
library(sp)
library(smoothr)

# kernel density
library(eks)
library(ggdensity)

# stat
library(Hmisc)
library(circular)
library(CircStats)

# char
library(stringr)

# solar angle
library(oce)

# data wrangling
library(tidyr)
library(dplyr)
library(purrr)
library(forcats)
library(lubridate)

2 Setting up custom function

2.1 windrose

Code
windrose <-
  function(data_to_plot,
           grid = NULL,
           set_title = NULL,
           legend_position = "none",
           facet = F) {
    # this code comes from Roxanne
    uniqhours <- 1:24 * (360 / 24)

    # trick to align hours om the graph
    data_to_plot <- rbind(data_to_plot[2:nrow(data_to_plot), ], data_to_plot[1, ])

    for (i in 1:24) {
      # turn hours to radians
      if (i == 1) {
        temp <- rep(uniqhours[i], data_to_plot$nb_ind_hour[i])
        day_night <- rep("night", data_to_plot$nb_ind_hour[i])
      } else {
        temp <- c(temp, rep(uniqhours[i], data_to_plot$nb_ind_hour[i]))
        day_night <- c(day_night, rep(
          if_else(between(i, 7, 20), "day", "night"),
          data_to_plot$nb_ind_hour[i]
        ))
      }
    }
    data2 <- data.frame(direction = temp)

    deg <- 15 # choose bin size (degrees/bin)
    dir.breaks <- seq(0 - (deg / 2), 360 + (deg / 2), deg) # define the range of each bin

    # assign each direction to a bin range
    dir.binned <-
      cut(data2$direction,
        breaks = dir.breaks,
        ordered_result = TRUE
      )
    # generate pretty lables
    dir.labels <- as.character(c(seq(0, 360 - deg, by = deg), 0))

    # replace ranges with pretty bin lables
    levels(dir.binned) <- dir.labels

    # Assign bin names to the original data set
    data2$dir.binned <- dir.binned

    # add origin if any
    if (facet) {
      data2$origin <- unique(data_to_plot$origin)
    }

    # set up max value
    maxvalue <- 35

    # initialise the plot
    plt.dirrose_2 <- ggplot()

    # check if grid
    if (!is.null(grid)) {
      plt.dirrose_2 <- plt.dirrose_2 +
        geom_hline(
          yintercept = grid,
          colour = "grey20",
          linewidth = .2
        )
    }
    plt.dirrose_2 <- plt.dirrose_2 +
      geom_vline(
        xintercept = c(seq(1, 24, 2)),
        colour = "grey30",
        linewidth = 0.2
      ) + # 24 vertical lines at center of the 30? ranges.
      geom_hline(
        yintercept = maxvalue,
        colour = "white",
        linewidth = .5
      ) + # Darker horizontal line as the top border (max).
      # On top of everything we place the histogram bars.
      geom_bar(
        data = data2,
        aes(x = dir.binned, fill = day_night),
        width = 1,
        colour = "black",
        linewidth = 0.3
      ) +
      # geom_bar(data = data2, aes(x = dir.binned2), width = 1, colour="black", size = 0.3,fill="salmon",alpha=0.9) +
      scale_x_discrete(
        drop = FALSE,
        labels = c(
          0, "", 2, "", 4, "", 6, "", 8, "", 10, "", 12, "", 14, "", 16, "", 18, "", 20, "", 22, ""
        )
      ) +
      scale_fill_manual(values = c("white", "darkgrey"), name = "Time of day") +
      labs(x = "Time (hours)", y = "Count", title = set_title) +
      coord_polar(start = -(deg / 2) * (pi / 180))

    # if facet
    if (facet) {
      plt.dirrose_2 <- plt.dirrose_2 +
        facet_wrap2(. ~ origin)
    }

    # Wraps the histogram into a windrose
    plt.dirrose_2 <- plt.dirrose_2 +
      theme_bw() +
      theme(
        legend.position = legend_position,
        panel.grid.minor = element_blank(),
        panel.grid.major = element_blank(),
        panel.background = element_blank(),
        legend.key.size = unit(0.5, "cm")
      )

    # return
    return(plt.dirrose_2)
  }

3 Import data

Let’s load data_dive, i.e. the output of data_wrangling.qmd, and filter only on animals leaving from Ano Nuevo.

Code
# import the data
data_dive <- readRDS("../export/data_dive.rds")

# filter on seals departing from ANNU
data_dive <- data_dive %>%
  filter(DepartureLocation == "ANNU")
Code
# get solar angle when data location
solar_angle_inter <- data_dive %>%
  filter(!is.na(Lat)) %>%
  mutate(solar_angle = sunAngle(date, Long, Lat)$altitude) %>%
  select(id, DiveNumber, solar_angle)

# merge that with data_dive
data_dive <- merge(data_dive,
  solar_angle_inter,
  by = c("id", "DiveNumber"),
  all.x = T
)

# change few things
data_dive <- data_dive %>%
  mutate(
    # add day-night
    day_night = if_else(solar_angle < -18, "night", "day"),
    # change divetype
    DiveType = data.table::fifelse(DiveType == 3 &
      (abs(bathy) - Maxdepth) > 100, 0, DiveType),
    DiveTypeName = data.table::fifelse(
      DiveTypeName == "Benthic" &
        (abs(bathy) - Maxdepth) > 100,
      "Transit",
      DiveTypeName
    )
  )

4 Data Visualisation

4.1 Table 1

Code
# shark and orca area = NA if no location data
data_dive <- data_dive %>%
  mutate(
    shark_area = if_else(is.na(Lat), NA, shark_area),
    orca_area = if_else(is.na(Lat), NA, orca_area)
  ) %>%
  # add year of deployment
  group_by(id) %>%
  mutate(
    year = first(format(date, format = "%Y")),
    shark_and_orca = if_else(is.na(Lat),
      NA,
      if_else(shark_area + orca_area == 2, 1, 0)
    ),
    shark_or_orca = if_else(is.na(Lat),
      NA,
      if_else(shark_area + orca_area >= 1, 1, 0)
    )
  )

# build table
data_dive %>%
  group_by(year, id) %>%
  summarise(
    n_dives_ind_all = length(DiveNumber),
    n_dives_ind_w_loc = length(DiveNumber[!is.na(Lat)]),
    n_dives_ind_wo_loc = length(DiveNumber[is.na(Lat)]),
    n_benthic_dives_all = length(DiveNumber[DiveTypeName == "Benthic"]),
    n_benthic_dives_w_loc = length(DiveNumber[DiveTypeName == "Benthic" & !is.na(Lat)]),
    n_benthic_dives_ind_in_shark = length(DiveNumber[DiveTypeName == "Benthic" &
      shark_area == 1 &
      !is.na(Lat)]),
    n_benthic_dives_ind_in_orca = length(DiveNumber[DiveTypeName == "Benthic" &
      orca_area == 1 &
      !is.na(Lat)]),
    n_benthic_dives_ind_shark_and_orca = length(DiveNumber[DiveTypeName == "Benthic" &
      shark_and_orca == 1 &
      !is.na(Lat)]),
    n_benthic_dives_ind_shark_or_orca = length(DiveNumber[DiveTypeName == "Benthic" &
      shark_or_orca == 1 &
      !is.na(Lat)]),
    hour_day_departure = first(as.numeric(format(date_tz[DiveTypeName == "Benthic"],
      format = "%H"
    ))),
    hour_day_arrival = last(as.numeric(format(date_tz[DiveTypeName == "Benthic"],
      format = "%H"
    ))),
    .groups = "drop"
  ) %>%
  group_by(year) %>%
  summarise(
    n_ind = length(id),
    n_dives_all = sum(n_dives_ind_all),
    n_dives_w_loc = sum(n_dives_ind_w_loc),
    n_dives_wo_loc = sum(n_dives_ind_wo_loc),
    n_benthic_dives = sum(n_benthic_dives_all),
    n_benthic_dives_proportion = sum(n_benthic_dives) / sum(n_dives_all),
    n_benthic_dives_in_shark_proportion = sum(n_benthic_dives_ind_in_shark) / sum(n_benthic_dives_w_loc),
    n_benthic_dives_in_orca_proportion = sum(n_benthic_dives_ind_in_orca) / sum(n_benthic_dives_w_loc),
    n_benthic_dives_in_shark_and_orca = sum(n_benthic_dives_ind_shark_and_orca) / sum(n_benthic_dives_w_loc),
    n_benthic_dives_in_shark_or_orca = sum(n_benthic_dives_ind_shark_or_orca) / sum(n_benthic_dives_w_loc),
    n_dives_mean = mean(n_dives_ind_all),
    n_dives_plus_minus = "<U+00B1>",
    n_dives_sd = sd(n_dives_ind_all),
    n_benthic_dives_mean = mean(n_benthic_dives_all),
    n_benthic_dives_plus_minus = "<U+00B1>",
    n_benthic_dives_sd = sd(n_benthic_dives_all),
    hour_day_departure_mean = psych::circadian.mean(hour_day_departure),
    hour_day_departure_plus_minus = "<U+00B1>",
    hour_day_departure_sd = psych::circadian.sd(hour_day_departure)$sd,
    hour_day_arrival_mean = psych::circadian.mean(hour_day_arrival),
    hour_day_arrival_plus_minus = "<U+00B1>",
    hour_day_arrival_sd = psych::circadian.sd(hour_day_arrival)$sd
  ) %>%
  gt() %>%
  tab_spanner(
    label = "All dives",
    columns = c(
      "n_dives_all",
      "n_dives_w_loc",
      "n_dives_wo_loc"
    )
  ) %>%
  tab_spanner(
    label = "Benthic dives",
    columns = c(
      "n_benthic_dives",
      "n_benthic_dives_proportion"
    )
  ) %>%
  tab_spanner(
    label = "% benthic dives",
    columns = c(
      "n_benthic_dives_in_shark_proportion",
      "n_benthic_dives_in_orca_proportion",
      "n_benthic_dives_in_shark_or_orca",
      "n_benthic_dives_in_shark_and_orca"
    )
  ) %>%
  tab_spanner(
    label = "# dives",
    columns = c(
      "n_dives_mean",
      "n_dives_plus_minus",
      "n_dives_sd"
    )
  ) %>%
  tab_spanner(
    label = "# benthic dives",
    columns = c(
      "n_benthic_dives_mean",
      "n_benthic_dives_plus_minus",
      "n_benthic_dives_sd"
    )
  ) %>%
  tab_spanner(
    label = "Hour departure",
    columns = c(
      "hour_day_departure_mean",
      "hour_day_departure_plus_minus",
      "hour_day_departure_sd"
    )
  ) %>%
  tab_spanner(
    label = "Hour arrival",
    columns = c(
      "hour_day_arrival_mean",
      "hour_day_arrival_plus_minus",
      "hour_day_arrival_sd"
    )
  ) %>%
  tab_spanner(
    label = "Per individuals",
    columns = c(
      "n_dives_mean",
      "n_dives_plus_minus",
      "n_dives_sd",
      "n_benthic_dives_mean",
      "n_benthic_dives_plus_minus",
      "n_benthic_dives_sd",
      "hour_day_departure_mean",
      "hour_day_departure_plus_minus",
      "hour_day_departure_sd",
      "hour_day_arrival_mean",
      "hour_day_arrival_plus_minus",
      "hour_day_arrival_sd"
    )
  ) %>%
  # rename columns
  cols_label(
    year = "Year",
    n_ind = "# seals",
    n_dives_all = "Total",
    n_dives_w_loc = "w/ loc",
    n_dives_wo_loc = "w/o loc",
    n_benthic_dives = "Total",
    n_benthic_dives_proportion = "Proportion",
    n_benthic_dives_in_shark_proportion = "Shark area",
    n_benthic_dives_in_orca_proportion = "Orca area",
    n_benthic_dives_in_shark_or_orca = "Full",
    n_benthic_dives_in_shark_and_orca = "Overlap",
    n_dives_mean = md("Mean"),
    n_dives_plus_minus = md("<U+00B1>"),
    n_dives_sd = md("SD"),
    n_benthic_dives_mean = md("Mean"),
    n_benthic_dives_plus_minus = md("<U+00B1>"),
    n_benthic_dives_sd = md("SD"),
    hour_day_departure_mean = md("Mean"),
    hour_day_departure_plus_minus = md("<U+00B1>"),
    hour_day_departure_sd = md("SD"),
    hour_day_arrival_mean = md("Mean"),
    hour_day_arrival_plus_minus = md("<U+00B1>"),
    hour_day_arrival_sd = md("SD")
  ) %>%
  fmt_percent(
    columns = c(
      "n_benthic_dives_in_shark_proportion",
      "n_benthic_dives_in_orca_proportion",
      "n_benthic_dives_proportion",
      "n_benthic_dives_in_shark_or_orca",
      "n_benthic_dives_in_shark_and_orca"
    ),
    decimal = 1
  ) %>%
  fmt_number(
    columns = c(
      "n_dives_all",
      "n_dives_w_loc",
      "n_dives_wo_loc",
      "n_benthic_dives"
    ),
    decimal = 0
  ) %>%
  fmt_number(
    columns = c(
      "n_dives_mean",
      "n_dives_sd",
      "n_benthic_dives_mean",
      "n_benthic_dives_sd",
      "hour_day_departure_mean",
      "hour_day_departure_sd",
      "hour_day_arrival_mean",
      "hour_day_arrival_sd"
    ),
    decimal = 1,
    use_seps = FALSE
  ) %>%
  # alignement
  cols_align(
    columns = c(
      "n_dives_sd",
      "n_benthic_dives_sd",
      "hour_day_departure_sd",
      "hour_day_arrival_sd"
    ),
    align = "left"
  ) %>%
  # color rows
  opt_row_striping() %>%
  tab_options(table.width = pct(150))
Per individuals
Year # seals All dives Benthic dives % benthic dives # dives # benthic dives Hour departure Hour arrival
Total w/ loc w/o loc Total Proportion Shark area Orca area Full Overlap Mean <U+00B1> SD Mean <U+00B1> SD Mean <U+00B1> SD Mean <U+00B1> SD
2004 26 280,155 215,452 64,703 9,291 3.3% 79.0% 100.0% 100.0% 79.0% 10775.2 <U+00B1> 3031.8 357.3 <U+00B1> 575.3 17.7 <U+00B1> 1.5 14.4 <U+00B1> 1.4
2005 35 281,636 226,566 55,070 16,413 5.8% 57.8% 100.0% 100.0% 57.8% 8046.7 <U+00B1> 3704.9 468.9 <U+00B1> 958.3 18.7 <U+00B1> 1.4 19.2 <U+00B1> 2.0
2006 29 219,773 181,667 38,106 5,219 2.4% 72.5% 100.0% 100.0% 72.5% 7578.4 <U+00B1> 3613.8 180.0 <U+00B1> 232.1 18.7 <U+00B1> 1.5 11.3 <U+00B1> 1.6
2007 30 235,691 235,691 0 5,829 2.5% 91.4% 100.0% 100.0% 91.4% 7856.4 <U+00B1> 3880.7 194.3 <U+00B1> 366.8 18.5 <U+00B1> 1.6 15.4 <U+00B1> 2.1
2008 35 252,268 239,800 12,468 3,460 1.4% 99.9% 100.0% 100.0% 99.9% 7207.7 <U+00B1> 3557.8 98.9 <U+00B1> 135.7 13.0 <U+00B1> 2.2 12.6 <U+00B1> 2.0
2009 24 149,429 135,010 14,419 3,646 2.4% 94.4% 100.0% 100.0% 94.4% 6226.2 <U+00B1> 3076.3 151.9 <U+00B1> 188.2 15.3 <U+00B1> 1.8 18.1 <U+00B1> 1.8
2010 35 248,956 248,956 0 3,702 1.5% 93.0% 100.0% 100.0% 93.0% 7113.0 <U+00B1> 3475.9 105.8 <U+00B1> 81.0 20.6 <U+00B1> 1.6 11.9 <U+00B1> 1.8
2011 32 244,228 232,301 11,927 3,883 1.6% 85.3% 100.0% 100.0% 85.3% 7632.1 <U+00B1> 3842.4 121.3 <U+00B1> 151.4 22.7 <U+00B1> 1.7 7.8 <U+00B1> 1.7
2012 33 256,295 256,295 0 4,233 1.7% 82.2% 100.0% 100.0% 82.2% 7766.5 <U+00B1> 4090.7 128.3 <U+00B1> 152.0 20.1 <U+00B1> 1.3 13.4 <U+00B1> 2.6
2013 31 265,526 265,526 0 5,149 1.9% 87.0% 100.0% 100.0% 87.0% 8565.4 <U+00B1> 4318.0 166.1 <U+00B1> 218.6 15.2 <U+00B1> 2.2 6.9 <U+00B1> 1.7
2014 22 141,911 141,911 0 6,679 4.7% 90.5% 100.0% 100.0% 90.5% 6450.5 <U+00B1> 3424.0 303.6 <U+00B1> 473.9 17.0 <U+00B1> 1.7 17.7 <U+00B1> 1.7
2015 30 226,090 226,090 0 4,380 1.9% 99.3% 100.0% 100.0% 99.3% 7536.3 <U+00B1> 3956.1 146.0 <U+00B1> 91.3 17.6 <U+00B1> 1.1 18.9 <U+00B1> 2.0
2016 27 215,401 215,401 0 4,003 1.9% 93.0% 100.0% 100.0% 93.0% 7977.8 <U+00B1> 4315.7 148.3 <U+00B1> 103.8 22.1 <U+00B1> 1.6 13.1 <U+00B1> 1.7
2017 10 75,326 75,326 0 1,648 2.2% 65.8% 100.0% 100.0% 65.8% 7532.6 <U+00B1> 3664.9 164.8 <U+00B1> 162.3 5.4 <U+00B1> 1.6 0.1 <U+00B1> 1.0
2018 18 150,599 146,164 4,435 2,733 1.8% 92.0% 100.0% 100.0% 92.0% 8366.6 <U+00B1> 3650.2 151.8 <U+00B1> 95.0 11.2 <U+00B1> 2.2 10.4 <U+00B1> 2.2
2019 7 32,823 32,823 0 769 2.3% 97.8% 100.0% 100.0% 97.8% 4689.0 <U+00B1> 1342.1 109.9 <U+00B1> 65.8 15.7 <U+00B1> 1.6 20.1 <U+00B1> 2.6
Next step
  • Wording
  • Adding/removing info

4.2 Figure 1

Let’s create a table specific for this figure that only contains for each individual:

  • the first dive
  • the last dive
  • all benthic dives
Code
# let's add a column with the local_time
data_windrose <- data_dive %>%
  # get rid of data without location information
  filter(!is.na(Lat)) %>%
  # then by individual
  group_by(id) %>%
  # keep only the first, last date, but also all benthic dives
  filter(date == min(date) |
    date == max(date) |
    DiveTypeName == "Benthic")
Code
hour_time_2_radian <- function(x, high = 24, low = 0) {
  # https://pingouin-stats.org/build/html/generated/pingouin.convert_angles.html#pingouin.convert_angles
  ptp <- high - low
  rad <- x * (2 * pi) / ptp
  rad <- (rad + pi) %% (2 * pi) - pi
  return(rad)
}
Code
# departure
test_departure <- CircStats::r.test(
  data_windrose %>%
    group_by(id) %>%
    filter(DiveNumber == 1) %>%
    mutate(time = hour(date_tz) +
      minute(date_tz) / 60 +
      second(date_tz) / (60 * 60)) %>%
    pull(time) %>%
    hour_time_2_radian(.)
)

# arrival
test_arrival <- r.test(conversion.circular(
  circular(
    data_windrose %>%
      group_by(id) %>%
      filter(date_tz == max(date_tz)) %>%
      mutate(time = hour(date_tz) +
        minute(date_tz) / 60 +
        second(date_tz) / (60 * 60)) %>% pull(time),
    units = "hours"
  ),
  units = "radians"
))

# benthic
test_benthic <- r.test(conversion.circular(
  circular(
    data_windrose %>%
      group_by(id) %>%
      filter(DiveTypeName == "Benthic") %>%
      mutate(time = hour(date_tz) +
        minute(date_tz) / 60 +
        second(date_tz) / (60 * 60)) %>%
      pull(time),
    units = "hours"
  ),
  units = "radians"
))

# convert back to hours
conversion.circular(
  circular(test_departure$r.bar,
    units = "radians"
  ),
  units = "hours"
)
Circular Data: 
Type = angles 
Units = hours 
Template = none 
Modulo = asis 
Zero = 0 
Rotation = counter 
[1] 0.8273588
Code
conversion.circular(
  circular(test_arrival$r.bar,
    units = "radians"
  ),
  units = "hours"
)
Circular Data: 
Type = angles 
Units = hours 
Template = none 
Modulo = asis 
Zero = 0 
Rotation = counter 
[1] 0.287106
Code
conversion.circular(
  circular(test_benthic$r.bar,
    units = "rad"
  ),
  units = "hours"
)
Circular Data: 
Type = angles 
Units = hours 
Template = none 
Modulo = asis 
Zero = 0 
Rotation = counter 
[1] 0.09631095
Code
# for departure
windrose_departure <- data_windrose %>%
  group_by(id) %>%
  filter(DiveNumber == 1) %>%
  mutate(time = as.numeric(format(date_tz, format = "%H"))) %>%
  group_by(time) %>%
  summarise(nb_ind_hour = n()) %>%
  mutate(origin = "Departure") %>%
  windrose(., grid = c(10, 20, 30), facet = T) +
  theme(axis.title.x = element_blank())

# for arrival
windrose_arrival <- data_windrose %>%
  group_by(id) %>%
  filter(date_tz == max(date_tz)) %>%
  mutate(time = as.numeric(format(date_tz, format = "%H"))) %>%
  group_by(time) %>%
  summarise(nb_ind_hour = n()) %>%
  mutate(origin = "Arrival") %>%
  windrose(., grid = c(10, 20, 30), legend_position = "top", facet = T) +
  theme(axis.title.y = element_blank())

# for benthic dives
windrose_benthic <- data_windrose %>%
  group_by(id) %>%
  filter(DiveTypeName == "Benthic") %>%
  mutate(time = as.numeric(format(date_tz, format = "%H"))) %>%
  group_by(time) %>%
  summarise(nb_ind_hour = n()) %>%
  mutate(origin = "Benthic") %>%
  windrose(., grid = c(3000, 6000, 9000), facet = T) +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# for benthic dives with angle
# windrose_angle_benthic <-
# data_windrose %>%
# group_by(id) %>%
# filter(DiveTypeName == "Benthic") %>%
# mutate(solar_angle_cut = as.numeric(trunc(solar_angle))) %>%
# group_by(solar_angle_cut) %>%
# summarise(nb_ind_hour = n()) %>%
# mutate(origin = "Benthic")  %>%
# ggplot(.,aes(x=solar_angle_cut,y=nb_ind_hour)) +
# geom_col() +
# geom_vline(xintercept = c(-6, -12, -18), linetype = "dashed")

# combine all
(windrose_departure + windrose_arrival + windrose_benthic) +
  plot_layout(
    guides = "collect"
  ) &
  theme(legend.position = "top")

Figure 1: Circular histogram plots displaying the times (in hours) of when female northern elephant seals (n = 403) perform their first recorded dive upon departing for their foraging trip (a), the last dive performed before returning from their foraging trip (b), and the time when they perform all benthic dives across their foraging trip (c).

Code
# departure
psych::circadian.mean(
  data_windrose %>%
    group_by(id) %>%
    filter(DiveNumber == 1) %>%
    mutate(time = hour(date_tz) +
      minute(date_tz) / 60 +
      second(date_tz) / (60 * 60)) %>% pull(time)
)
[1] 19.30606
Code
# arrival
psych::circadian.mean(
  data_windrose %>%
    group_by(id) %>%
    filter(date_tz == max(date_tz)) %>%
    mutate(time = hour(date_tz) +
      minute(date_tz) / 60 +
      second(date_tz) / (60 * 60)) %>% pull(time)
)
[1] 14.30181
Code
# benthic
psych::circadian.mean(
  data_windrose %>%
    group_by(id) %>%
    filter(DiveTypeName == "Benthic") %>%
    mutate(time = hour(date_tz) +
      minute(date_tz) / 60 +
      second(date_tz) / (60 * 60)) %>% pull(time)
)
[1] 1.507163
Next step
  • Circular stats… again!

4.3 Figure 2

Tip

This part is mostly based on https://cran.r-project.org/web/packages/eks/vignettes/tidysf_kde.html. The author of the package confirms that his kernel density estimation is calculated using “meaningful” units such as UTM 1, since the input is in a simple feature format.

Code
# data use to compute kernel density estimation
df_kernel_dens <- data_dive %>%
  # only with location data
  filter(!is.na(Lat)) %>%
  # select only the required columns
  select(lat = Lat, long = Long, id, DiveTypeName) %>%
  # create col to nicely display dive type
  mutate(origin = paste(DiveTypeName, "dives"))
Code
# check if background_ggoceanmaps exist
if (file.exists("../export/background_ggoceanmap.rds")) {
  trip <- readRDS("../export/background_ggoceanmap.rds")
} else {
  # using ggOceanMaps
  trip <- basemap(
    limits = c(170, -110, 20, 59),
    bathymetry = TRUE,
    shapefiles = "Arctic",
    rotate = TRUE,
    grid.col = NA
  )

  # Make the graticules:
  lims <- attributes(trip)$limits
  graticule <- sf::st_graticule(
    c(lims[1], lims[3], lims[2], lims[4]),
    crs = attributes(trip)$proj,
    lon = seq(-180, 180, 45),
    lat = seq(-90, 90, 10)
  )

  # Plot
  trip <- trip +
    geom_sf(data = graticule, color = "grey50")

  trip$layers <- trip$layers[c(1, 3, 2)]

  # save result
  saveRDS(trip, "../export/background_ggoceanmap.rds")
}
Code
# transform data into sf object
df_kernel_dens_sf <- st_as_sf(
  df_kernel_dens,
  coords = c("long", "lat"),
  crs = st_crs(4326)
)

# make it's group_by origin
df_kernel_dens_sf <- group_by(df_kernel_dens_sf, origin)

# kernel density estimation
df_kernel_dens_sf_kde <- st_kde(df_kernel_dens_sf,
  H = diag(c(
    MASS::bandwidth.nrd(
      sf::st_coordinates(df_kernel_dens_sf)[, 1]
    ),
    MASS::bandwidth.nrd(
      sf::st_coordinates(df_kernel_dens_sf)[, 2]
    )
  ) / 4)^2
)

# https://github.com/r-spatial/sf/issues/1762
sf::sf_use_s2(FALSE)

# plot
trip +
  # new scale
  new_scale_fill() +
  # kernel
  geom_sf(
    data = st_get_contour(
      # geospatial kernel
      df_kernel_dens_sf_kde,
      # probabilities
      cont = c(50, 80, 95, 99)
    ),
    # display
    aes(fill = label_percent(contlabel)),
    alpha = 0.7
  ) +
  # same colour bar
  scale_fill_viridis_d(option = "plasma") +
  # legend
  labs(fill = "Probs") +
  # no display alpha
  guides(alpha = "none") +
  # facet by origin
  facet_wrap(. ~ origin)

Figure 2: Kernel density plots of the dives performed by female northern elephant seals (n = 403) during their foraging trips separated by each of the four dive types. Level indicates the concentration of dives with red showing the highest concentration. Seals all departed and returned from Año Nuevo State Park.

Next step
  • see if it worth adding the North arrow and a scale

This was the original way, but due to packages updates, I decided to switch with eks + ggOceanMaps option.

Code
# register to query google API
register_google(key = readChar(
  "../key/api_key.txt",
  file.info("../key/api_key.txt")$size
))

# get the map
trip_bis <- qmplot(
  long,
  lat,
  # weird, doesn't work if I increase nb of locations...
  data = df_kernel_dens %>%
    group_by(origin) %>%
    filter(row_number() < 1000),
  geom = "blank",
  zoom = 3,
  maptype = "satellite",
  source = "google"
)

# maps
trip_bis +
  # kernel
  geom_hdr(
    data = df_kernel_dens,
    aes(x = long, y = lat, fill = after_stat(probs))
  ) +
  # remove some legend
  guides(alpha = "none") +
  labs(fill = "Probs") +
  # facet
  facet_wrap2(. ~ origin)

Figure 3: Same but performed with ggdensity package

4.4 Figure 3

Code
# get predator distribution (extraction using google earth)
Shark_area_coord <- read_sf("../export/shark.kmz") %>%
  smooth(., method = "ksmooth", smoothness = 0.5) %>%
  # st_crop(., xmin = 170, xmax = -110, ymin = 20, ymax = 59) %>%
  st_coordinates() %>%
  as_tibble() %>%
  select(lon = X, lat = Y)
Orca_area_coord <- read_sf("../export/orca.kmz") %>%
  smooth(., method = "ksmooth", smoothness = 0.5) %>%
  # st_crop(., xmin = 170, xmax = -110, ymin = 20, ymax = 59) %>%
  st_coordinates() %>%
  as_tibble() %>%
  select(lon = X, lat = Y)
Code
# add inside/outside each area
data_dive <- data_dive %>%
  mutate(
    shark_area = point.in.polygon(
      point.x = Long,
      point.y = Lat,
      pol.x = Shark_area_coord$lon,
      pol.y = Shark_area_coord$lat
    ),
    orca_area = point.in.polygon(
      point.x = Long,
      point.y = Lat,
      pol.x = Orca_area_coord$lon,
      pol.y = Orca_area_coord$lat
    ),
    overlap_area = as.numeric(if_else(shark_area == 1 &
      orca_area == 1, T, F)),
    full_area = as.numeric(if_else(shark_area == 0 &
      orca_area == 0, F, T))
  )
Code
data_dive_longer <- pivot_longer(
  data_dive,
  c(
    "shark_area",
    "orca_area",
    "overlap_area",
    "full_area"
  ),
  names_to = "areas",
  values_to = "in_out"
)

data_descriptive_ind <- data_dive_longer %>%
  filter(DiveTypeName == "Benthic") %>%
  group_by(areas, id) %>%
  summarise(
    n_tot = n(),
    n_inside = length(id[in_out == 1]),
    n_outside = length(id[in_out == 0]),
    .groups = "drop"
  ) %>%
  mutate(
    perc_inside = n_inside / n_tot,
    perc_outside = n_outside / n_tot
  )

data_descriptive_area <- data_descriptive_ind %>%
  group_by(areas) %>%
  summarise(
    mean_perc_inside = wtd.mean(perc_inside, n_tot),
    mean_perc_outside = wtd.mean(perc_outside, n_tot),
    sd_perc_inside = sqrt(wtd.var(perc_inside, n_tot)),
    sd_perc_outside = sqrt(wtd.var(perc_outside, n_tot)),
    # based from here: https://stats.stackexchange.com/questions/25895/computing-standard-error-in-weighted-mean-estimation
    se_perc_inside = sqrt(wtd.var(perc_inside, n_tot) * sum((n_tot / sum(n_tot))^2)),
    se_perc_outside = sqrt(wtd.var(perc_outside, n_tot) * sum((n_tot / sum(n_tot))^2)),
  ) %>%
  pivot_longer(
    cols = ends_with("inside") |
      ends_with("outside"),
    names_to = c("stat", "in_out"),
    names_pattern = "(.*)_perc_(.*)"
  ) %>%
  pivot_wider(
    id_cols = c("areas", "in_out"),
    names_from = "stat",
    values_from = "value"
  ) %>%
  mutate(areas = factor(areas,
    level = c(
      "overlap_area",
      "orca_area",
      "shark_area",
      "full_area"
    )
  ))

data_stat_area <- data_dive_longer %>%
  filter(DiveTypeName == "Benthic") %>%
  group_by(areas, in_out) %>%
  summarise(nb_area = n(), .groups = "drop_last") %>%
  mutate(nb_total = sum(nb_area)) %>%
  summarise(rstatix::prop_test(x = nb_area, n = nb_total))
Code
# geom_signif(
#   # y_position = data_descriptive_area %>%
#   #   mutate(N = mean + sd) %>%
#   #   select(N) %>%
#   #   pull() %>%
#   #   max() + 0.05,
#   y_position = 0.5,
#   xmin = c(0.6, 1.6, 2.6, 3.6),
#   xmax = c(1.4, 2.4, 3.4, 4.4),
#   annotations = if_else(
#     data_stat_area$p.signif == "****",
#     "***",
#     data_stat_area$p.signif
#   )
# ) +
Code
inside_bar_plot <- data_descriptive_area %>%
  mutate(
    mean = if_else(in_out == "outside", -mean, mean),
    sd = if_else(in_out == "outside", -sd, sd),
    se = if_else(in_out == "outside", -se, se)
  ) %>%
  filter(in_out == "inside") %>%
  ggplot(aes(x = mean, y = areas, fill = areas)) +
  facet_grid(in_out ~ ., scales = "free_y") +
  geom_col(show.legend = F) +
  scale_fill_manual(values = c("#E1E826", "#E66100", "#9A6BEC", "#004D40")) +
  new_scale_fill() +
  geom_col(
    show.legend = F,
    mapping = aes(
      x = mean,
      y = areas,
      fill = in_out
    ),
    alpha = 0.3
  ) +
  scale_fill_manual(values = c("grey70")) +
  geom_errorbar(
    mapping = aes(
      xmin = -se,
      xmax = se
    ),
    # reduce size of horizontal bar of the errorbar
    width = 0.05
  ) +
  coord_flip(xlim = c(0, max(data_descriptive_area$mean))) +
  scale_x_continuous(
    breaks = c(-0.6, -0.4, -0.2, 0.2, 0.4, 0.6),
    expand = c(0, 0),
    labels = function(x) {
      scales::percent(abs(x), 1)
    }
  ) +
  scale_y_discrete(
    labels = function(x) {
      lapply(x, function(x) {
        (str_split(str_to_title(x), "_"))[[1]][1]
      })
    }
  ) +
  theme(
    panel.spacing.y = unit(0, "mm"),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line.y = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    )),
    axis.title = element_blank(),
    axis.ticks.length.x = unit(0, units = "mm"),
    axis.text.x = element_blank()
  )

outside_bar_plot <- data_descriptive_area %>%
  mutate(
    mean = if_else(in_out == "outside", -mean, mean),
    sd = if_else(in_out == "outside", -sd, sd),
    se = if_else(in_out == "outside", -se, se)
  ) %>%
  filter(in_out == "outside") %>%
  ggplot(aes(x = mean, y = areas, fill = areas)) +
  facet_grid(in_out ~ ., scales = "free_y") +
  geom_col(show.legend = F) +
  scale_fill_manual(values = c("#E1E826", "#E66100", "#9A6BEC", "#004D40")) +
  new_scale_fill() +
  geom_col(
    show.legend = F, mapping = aes(
      x = mean,
      y = areas,
      fill = in_out
    ),
    alpha = 0.3
  ) +
  scale_fill_manual(values = c("grey30")) +
  geom_errorbar(
    mapping = aes(
      xmin = -se,
      xmax = se
    ),
    # reduce size of horizontal bar of the errorbar
    width = 0.05
  ) +
  coord_flip(xlim = c(-max(data_descriptive_area$mean), 0)) +
  scale_x_continuous(
    # breaks = c(-0.6, -0.4, -0.2, 0.2, 0.4, 0.6),
    expand = c(0, 0),
    labels = function(x) {
      scales::percent(abs(x), 1)
    }
  ) +
  scale_y_discrete(
    labels = function(x) {
      lapply(x, function(x) (str_split(str_to_title(x), "_"))[[1]][1])
    }
  ) +
  labs(y = "Areas") +
  theme(
    panel.spacing.y = unit(0, "mm"),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line.y = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed",
      ends = "first"
    )),
    axis.ticks.length.x = unit(0, units = "mm"),
    axis.title.y = element_blank()
  )

label_x_bar_plot <- ggplot(data.frame(
  l = "Percentage of benthic dives",
  x = 1,
  y = 1
)) +
  geom_text(aes(x, y, label = l, angle = 90)) +
  theme(
    aspect.ratio = 10,
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank()
  ) +
  theme_void()
Code
layout <- "
ABBBBBBBBBBB
ACCCCCCCCCCC
"

predator_stat_choice_1 <- label_x_bar_plot +
  #
  (inside_bar_plot + theme(plot.margin = unit(c(0, 0, 0, 0), "pt"))) +
  (outside_bar_plot + theme(plot.margin = unit(c(0, 0, 0, 0), "pt"))) +
  plot_layout(design = layout)
Code
# https://stackoverflow.com/questions/55015088/back-to-back-barplot-with-independent-axes-r
predator_stat_choice_2 <- data_descriptive_area %>%
  ggplot(aes(y = mean, x = areas, fill = areas)) +
  geom_bar(position = "fill", stat = "identity", show.legend = F) +
  scale_fill_manual(values = c("#E1E826", "#E66100", "#9A6BEC", "#004D40")) +
  new_scale_fill() +
  geom_bar(
    mapping = aes(
      y = mean,
      x = areas,
      fill = in_out
    ),
    alpha = 0.3,
    position = "fill",
    stat = "identity"
  ) +
  scale_fill_manual(values = c("grey70", "grey30")) +
  geom_errorbar(
    data = data_descriptive_area %>% filter(in_out == "outside"),
    mapping = aes(
      ymin = mean - se,
      ymax = mean + se
    ),
    # reduce size of horizontal bar of the errorbar
    width = 0.05
  ) +
  scale_y_continuous(
    labels = function(x) {
      scales::percent(abs(x), 1)
    }
  ) +
  scale_x_discrete(
    labels = function(x) {
      lapply(x, function(x) (str_split(str_to_title(x), "_"))[[1]][1])
    }
  ) +
  labs(x = "Areas", y = "Percentage of benthic dives", fill = "Status") +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line.y = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    )),
    axis.ticks.length.x = unit(0, units = "mm")
  )
Code
# color palette
# https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40
# combine areas
areas_coord <- rbind(
  Shark_area_coord %>% mutate(Predator = "shark"),
  Orca_area_coord %>% mutate(Predator = "orca")
)

# plot
predator_map <- trip +
  # new scale
  new_scale_fill() +
  # add point
  geom_spatial_point(
    data = data_dive %>%
      filter(DiveTypeName == "Benthic"),
    aes(x = Long, y = Lat, fill = "black"),
    alpha = 0.05,
    shape = 20,
    stroke = NA,
    crs = 4326
  ) +
  # color palette
  scale_fill_manual(
    name = "Dive",
    labels = "Benthic",
    values = "black"
  ) +
  # should I display legend?
  guides(fill = "none") +
  # new scale
  new_scale_fill() +
  # add spatial polygon
  geom_spatial_polygon(
    data = areas_coord,
    aes(
      x = lon,
      y = lat,
      fill = Predator,
      col = Predator
    ),
    alpha = .5,
    crs = 4326
  ) +
  # color palette
  scale_fill_manual(
    values = c("#E66100", "#9A6BEC")
  ) +
  scale_color_manual(
    values = c("#E66100", "#9A6BEC")
  ) +
  # set limit from predator_map$layers[[1]]$data
  coord_sf(
    xlim = c(-5579139, 5579139),
    ylim = c(-8679599, -2642510)
  )

# reordering layers (continent on top)
predator_map$layers <-
  c(
    predator_map$layers[c(1:2, 4:length(predator_map$layers))],
    predator_map$layers[3]
  )
Code
# layout
layout <- "
#AAAAAAAAAAAAAAAAAAAAAAA
#AAAAAAAAAAAAAAAAAAAAAAA
#AAAAAAAAAAAAAAAAAAAAAAA
BCCCCCCCCCCCCCCCCCCCCCCC
BDDDDDDDDDDDDDDDDDDDDDDD
"

# display
(predator_map + theme(legend.position = "none")) +
  (label_x_bar_plot + theme(plot.margin = unit(c(0, 0, 0, 0), "pt"))) +
  (inside_bar_plot + theme(plot.margin = unit(c(0, 0, 0, 0), "pt"))) +
  (outside_bar_plot + theme(plot.margin = unit(c(0, 0, 0, 0), "pt"))) +
  plot_layout(design = layout)

Figure 4: Overlap of female northern elephant seal’s trip (n=424) and predator habitat along with the percentage of benthic dives occurring inside as compared to outside of the habitat. The white star indicates the location of Año Nuevo State Park. Map a) displays orca and shark habitat along the west coast (adapted from Jorgenson, et al. 2019) and black lines represent the trip of all female northern elephant seals studied. Bar graph displays the average percentage of benthic dives occurring either inside or outside of orca habitat and displays the average percentage of benthic dives occurring inside and outside of shark habitat.

Next steps
  • see if it worth adding the North arrow and a scale
  • add the result of the test (inside vs. outside)
  • do we actually need legend for the map (area + bathymetry)?

4.5 Figure 4

Code
# main plot
bathy_prop <- data_dive %>%
  # keep only negative bathy
  filter(bathy < 0) %>%
  # and remove outliers
  filter(bathy > -6000) %>%
  # create class of bathymetry
  mutate(bathy_class = fct_rev(cut(
    bathy,
    seq(-6000, 0, 400),
    ordered_result = T,
    dig.lab = 4
  ))) %>%
  # calculate by bath_class and animal
  group_by(bathy_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # and divide by the total number of dives per bathy_class
  group_by(bathy_class) %>%
  # to get the percentage of different dive types per bathy_class
  mutate(percentage = N / sum(N)) %>%
  # ungroup => not required but that let the dataset clean
  ungroup() %>%
  # then plot
  ggplot(aes(x = bathy_class, y = percentage)) +
  # the area
  geom_area(aes(fill = DiveTypeName, group = DiveTypeName)) +
  # orientation of x labels
  guides(x = guide_axis(angle = 45)) +
  # format y axis
  scale_y_continuous(
    labels = function(x) {
      paste0(x * 100, "%")
    }
  ) +
  labs(
    x = "Bathymetry  (m)",
    y = "Dive type proportion (%)"
  ) +
  scale_fill_viridis(
    "Dive Type",
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  # scale_fill_manual("Dive Type", values = c("#fcfdbf", "#fc8961", "#b73779", "#51127c"))
  # position legend at the top
  theme(
    legend.position = "none",
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    ))
  )

# second plot
bathy_hist <- data_dive %>%
  # keep only negative bathy
  filter(bathy < 0) %>%
  # and remove outliers
  filter(bathy > -6000) %>%
  # create class of bathymetry
  mutate(bathy_class = fct_rev(cut(
    bathy,
    seq(-6000, 0, 400),
    ordered_result = T,
    dig.lab = 4
  ))) %>%
  # calculate by bath_class and animal
  group_by(bathy_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # ggplot
  ggplot(aes(
    x = bathy_class,
    y = N,
    fill = DiveTypeName,
    width = 0.5
  )) +
  geom_bar(
    stat = "identity",
    position = "dodge"
  ) +
  scale_fill_viridis(
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  theme_void() +
  theme(legend.position = "top")

# the actual plot
bath_plot <- bathy_hist / bathy_prop + plot_layout(heights = c(1, 10))
Code
# main plot
dist_coast_prop <- data_dive %>%
  # filter out animal without dist_coast
  filter(dist_coast > 0) %>%
  # remove outliers
  filter(dist_coast * 1000 * 111 <= 1900) %>%
  # create class of bathymetry
  mutate(dist_class = cut(
    # convert decimal degree/1000
    dist_coast * 1000 * 111,
    seq(0, 1900, 100),
    ordered_result = T,
    dig.lab = 4
  )) %>%
  # calculate by bath_class and animal
  group_by(dist_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # and divide by the total number of dives per dist_class
  group_by(dist_class) %>%
  # to get the percentage of different dive types per dist_class
  mutate(percentage = N / sum(N)) %>%
  # ungroup => not required but that let the dataset clean
  ungroup() %>%
  # then plot
  ggplot(aes(x = dist_class, y = percentage)) +
  # the area
  geom_area(aes(fill = DiveTypeName, group = DiveTypeName)) +
  # orientation of x labels
  guides(x = guide_axis(angle = 45)) +
  # format y axis
  scale_y_continuous(
    labels = function(x) {
      paste0(x * 100, "%")
    }
  ) +
  labs(
    x = "Distance from the coast (km)",
    y = "Dive type proportion (%)"
  ) +
  scale_fill_viridis(
    "Dive Type",
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  # scale_fill_manual("Dive Type", values = c("#fcfdbf", "#fc8961", "#b73779", "#51127c"))
  # position legend at the top
  theme(
    legend.position = "none",
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    ))
  )

# the second plot
dist_coast_hist <- data_dive %>%
  # filter out animal without dist_coast
  filter(dist_coast > 0) %>%
  # remove outliers
  filter(dist_coast * 1000 * 111 <= 1900) %>%
  # create class of bathymetry
  mutate(dist_class = cut(
    # convert decimal degree/1000
    dist_coast * 1000 * 111,
    seq(0, 2000, 100),
    ordered_result = T,
    dig.lab = 4
  )) %>%
  # calculate by bath_class and animal
  group_by(dist_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # ggplot
  ggplot(aes(
    x = dist_class,
    y = N,
    fill = DiveTypeName,
    width = 0.5
  )) +
  geom_bar(
    stat = "identity",
    position = "dodge"
  ) +
  scale_fill_viridis(
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  theme_void() +
  theme(legend.position = "top")

# the actual plot
dist_coast_plot <- dist_coast_hist / dist_coast_prop + plot_layout(heights = c(1, 10))
Code
# the main plot
dist_dep_prop <- data_dive %>%
  # filter out animal without dist_coast
  filter(dist_dep > 0) %>%
  # remove outliers
  filter(dist_dep / 1000 < 4200) %>%
  # create class of bathymetry
  mutate(dist_class = cut(
    dist_dep / 1000,
    seq(0, 4200, 300),
    ordered_result = T,
    dig.lab = 4
  )) %>%
  # calculate by bath_class and animal
  group_by(dist_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # and divide by the total number of dives per dist_class
  group_by(dist_class) %>%
  # to get the percentage of different dive types per dist_class
  mutate(percentage = N / sum(N)) %>%
  # ungroup => not required but that let the dataset clean
  ungroup() %>%
  # then plot
  ggplot(aes(x = dist_class, y = percentage)) +
  # the area
  geom_area(aes(fill = DiveTypeName, group = DiveTypeName)) +
  # orientation of x labels
  guides(x = guide_axis(angle = 45)) +
  # format y axis
  scale_y_continuous(
    labels = function(x) {
      paste0(x * 100, "%")
    }
  ) +
  labs(
    x = "Distance from departure (km)",
    y = "Dive type proportion (%)"
  ) +
  scale_fill_viridis(
    "Dive Type",
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  # scale_fill_manual("Dive Type", values = c("#fcfdbf", "#fc8961", "#b73779", "#51127c"))
  # position legend at the top
  theme(
    legend.position = "none",
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    ))
  )

# the second plot
dist_dep_hist <- data_dive %>%
  # filter out animal without dist_coast
  filter(dist_coast > 0) %>%
  # remove outliers
  filter(dist_dep / 1000 < 4200) %>%
  # create class of bathymetry
  mutate(dist_class = cut(
    dist_dep / 1000,
    seq(0, 4200, 300),
    ordered_result = T,
    dig.lab = 4
  )) %>%
  # calculate by bath_class and animal
  group_by(dist_class, DiveTypeName) %>%
  # the number of dives
  summarise(N = n(), .groups = "drop") %>%
  # ggplot
  ggplot(aes(
    x = dist_class,
    y = N,
    fill = DiveTypeName,
    width = 0.5
  )) +
  geom_bar(
    stat = "identity",
    position = "dodge"
  ) +
  scale_fill_viridis(
    option = "plasma",
    discrete = T,
    direction = -1
  ) +
  theme_void() +
  theme(legend.position = "top")

# the actual plot
dist_dep_plot <- dist_dep_hist / dist_dep_prop + plot_layout(heights = c(1, 10))
Code
# display
(guide_area() + bath_plot + dist_coast_plot + dist_dep_plot) +
  plot_layout(nrow = 5, guides = "collect")

Figure 5: Proportion of dives performed across entire trip separated by dive type across bathymetry intervals and distance from departure intervals, and displays the proportion of benthic dives occurring over the seals time spent at sea. For graph the largest percentage of benthic dives occurs at the lowest depth then occurs again at higher depths. For graph The highest percentage of benthic dives occurs at the lowest distance from where the seal is first assumed to have departed.

Next step
  • Try to keep a similar number of classes among figures

4.6 Figure 5

Code
# the last plot
prop_at_sea <- data_dive %>%
  group_by(id) %>%
  # time difference between the first date and the others (telling R to take diff b/w first date and all other dates)
  mutate(nb_days_departure = trunc(as.numeric(difftime(
    date, first(date),
    units = "days"
  )))) %>%
  # group by day/dive_type/seal
  group_by(nb_days_departure, DiveTypeName, id) %>%
  # count number of dives
  summarise(nb_daily_dives_type = n(), .groups = "drop") %>%
  # group by day/seal
  group_by(nb_days_departure, id) %>%
  # count the total number of dives per day/seal
  mutate(nb_daily_dives = sum(nb_daily_dives_type)) %>%
  # calculation of the proportion
  mutate(prop = nb_daily_dives_type / nb_daily_dives) %>%
  # order by seals/date
  arrange(id, nb_days_departure) %>%
  # perform our calculation per seal
  group_by(id) %>%
  # calculate of the percentage of time since departure
  mutate(perc_time_at_sea = round(nb_days_departure / max(nb_days_departure) * 100, 1)) %>%
  # focus on benthic dives
  filter(DiveTypeName == "Benthic") %>%
  # add class of percentage of time at sea
  mutate(day_class = cut(perc_time_at_sea, seq(0, 100, 5),
    include.lowest = T
  )) %>%
  # by class of percentage of time at sea
  group_by(day_class) %>%
  # calculate the proportion of daily benthic dives
  summarise(
    nb_benthic_class = sum(nb_daily_dives_type),
    nb_total_class = sum(nb_daily_dives),
    prop_class = nb_benthic_class / nb_total_class
  ) %>%
  # plot
  ggplot(
    .,
    aes(x = day_class, y = prop_class)
  ) +
  geom_bar(stat = "identity", fill = "grey", col = "grey30") +
  guides(x = guide_axis(angle = 45)) +
  scale_y_continuous(
    labels = function(x) {
      scales::percent(abs(x), 1)
    }
  ) +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    axis.line = element_line(arrow = arrow(
      angle = 20,
      length = unit(.10, "inches"),
      type = "closed"
    ))
  ) +
  labs(
    x = "Time spent at sea (%)",
    y = "Daily proportion of benthic dives (%)"
  )
Code
# display
prop_at_sea

Figure 6: Distribution of the percentage of benthic dives during elephant seals’ trip to sea expressed as a percentage of time spent at sea.

4.7 Extra

Code
# import the csv export
data_plot <- readr::read_csv("../data/benthic_dive_extract.csv")

# plot
data_plot %>%
  ggplot(aes(x = time, y = CorrectedDepth)) +
  geom_path() +
  scale_y_reverse() +
  theme_minimal() +
  theme(
    axis.line.y = element_line(arrow = arrow(
      type = "closed",
      ends = "first",
      length = unit(0.1, "inches")
    )),
    axis.line.x = element_line(arrow = arrow(
      type = "closed",
      ends = "last",
      length = unit(0.1, "inches")
    ))
  ) +
  labs(
    x = "Time",
    y = "Depth (m)"
  ) +
  geom_text(
    data = data.frame(
      xpos = median(data_plot$time),
      ypos = 30,
      hjustvar = 0,
      vjustvar = 0,
      annotateText = paste0(
        "Corner index: ", round(unique(data_plot$corner_index), 2),
        "\n",
        "Benthix index: ", round(unique(data_plot$benthic_index)), 2
      )
    ),
    aes(
      x = xpos, y = ypos, hjust = hjustvar,
      vjust = vjustvar, label = annotateText
    )
  ) +
  scale_x_datetime(position = "top") +
  labs(subtitle = "ID: 2011034 - Dive: 29")